package org.eclipse.jdt.core;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import x.java.io.File;
import x.java.io.FileInputStream;
import x.java.io.FileOutputStream;

/**
 * @author qiangli
 * 
 */
public class Classpath {
	private URL url = null;
	private File file = null;
	private ZipFile zip = null;

	private boolean directory = false;

	/*
	public Classpath(URL url) throws IOException {
		if (url.getProtocol().equals("file")) {
			this.file = new File(url.getPath()).getCanonicalFile();
			directory = file.isDirectory();
			if (!directory) {
				zip = new ZipFile(file);
			}
		} else {
			this.url = url;
			directory = url.getPath().endsWith("/");
			// postpone downloading for zip file
		}
	}
	*/

	public Classpath(File file) throws IOException {
		this.file = file;
		directory = file.isDirectory();
		if (!directory) {
			zip = new ZipFile(file);
		}
	}

	public URL getUrl() {
		return url;
	}

	public File getFile() {
		return file;
	}

	public ZipFile getZip() {
		return zip;
	}

	public boolean isDirectory() {
		return directory;
	}

	/**
	 * 
	 * @param name
	 *            relative pathname e.g java/lang/String.class
	 * @return
	 * @throws Exception
	 */
	public InputStream getResourceAsStream(String name) throws IOException {
		if (directory) {
			if (file != null) {
				File f = new File(file, name);
				if (f.exists()) {
					return new FileInputStream(f);
				}
				return null;
			}
			if (url != null) {
				URL u = new URL(url, name);
				return u.openStream();
			}
		}
		// archive file
		if (zip != null) {
			return readEntry(name);
		}

		// jar archive url
		if (url != null) {
			download();
			return readEntry(name);
		}
		
		return null;
	}

	private InputStream readEntry(String name) {
		InputStream is = null;
		try {
			ZipEntry ze = zip.getEntry(name);
			
			if (ze == null) {
				return null;
			}
			is = zip.getInputStream(ze);
			if (is == null) {
				throw new IOException("Invalid zip entry name : "
						+ ze.getName());
			}
			return is;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	private void download() throws IOException {
		URLConnection conn = url.openConnection();
		InputStream in = null;
		OutputStream out = null;
		try {
			in = conn.getInputStream();
			File f = (File)File.createTempFile("cp", ".zip");
			f.deleteOnExit();
			out = new FileOutputStream(f);
			byte[] b = new byte[1024];
			while (true) {
				int read = in.read(b);
				if (read == -1) {
					break;
				}
				out.write(b, 0, read);
			}
			zip = new ZipFile(f);
		} finally {
			try {
				in.close();
			} catch (Exception e) {
			}
			try {
				out.close();
			} catch (Exception e) {
			}
		}
	}
	
	public URL findResource(String name) throws IOException {

		if (directory) {
			if (file != null) {
				File f = new File(file, name);
				if (f.exists()) {
					return f.toURL();
				}
				return null;
			}
			if (url != null) {
				URL u = new URL(url, name);
				InputStream in = u.openConnection().getInputStream();
				if (in != null) {
					return u;
				}
			}
		}
		// archive file
		
		if (zip != null) {
			ZipEntry ze = zip.getEntry(name);	
			
			if (ze != null) {		
				return toURL(name);
			}
		}

		// jar archive url
		if (url != null) {
			download();
			//
			ZipEntry ze = zip.getEntry(name);	
			if (ze != null) {
				return toURL(name);
			}
		}

		return null;
	}
	
	private URL toURL(String name) throws MalformedURLException  {
		String p = zip.getName().replace(File.separatorChar,'/');
		if (!p.startsWith("/")) {
			p = "/"+p;
		}
		URL u = new URL("jar:file:"+p+"!/"+name);
		System.err.println("==========found URL: "+u);
		return u;
	}
	
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append("url: "+url);
		sb.append(" file: "+file);
		sb.append(" zip: "+zip);
		sb.append(" directory: "+directory);
		return sb.toString();
	}
}
